#include<iostream>
#include<stack>
#include<string>
#include<map>
#include<sstream>
#include<fstream>
using namespace std;

const string infixToPostfix(const string &infix);
void ifGetdigit(char ch, string &postfix);
void ifGetOperator(char ch, string &postfix, stack<char> &Stack_operators);
void isLeftParenthesis(char ch, stack<char> &Stack_operators);
void isRightParenthesis(string &postfix, stack<char> &Stack_operators);
void isArithmeticOperator(char ch, string &postfix, stack<char> &Stack_operators);
bool lastOneIsRightParenthesis(const string &postfix);
void appendOperatorsLeft(string &postfix, stack<char> Stack_operators);
double calculate(const string &postfix);
char putOperandsIntoStack(istringstream &in, stack<double> &operand);
void singleOperate(char ch, stack<double> &operand);

int main(void) {

	string expression;
	ifstream fin("in.txt");

	if (!fin.is_open()) {
		exit(EXIT_FAILURE);
	}

	while (!fin.eof()) {
		getline(fin, expression);
		cout << expression << " = " << calculate(infixToPostfix(expression)) << endl;
	}

	std::system("pause");
	return 0;
}


const string infixToPostfix(const string &infix) {

	istringstream fin(infix);
	stack<char> Stack_operators;
	string postfix;
	char ch;

	while (!fin.eof()) {
		if (fin >> ch) {
			if (isdigit(ch) || ch == '.')
				ifGetdigit(ch, postfix);
			else {
				ifGetOperator(ch, postfix, Stack_operators);
			}
		}
	}
	appendOperatorsLeft(postfix, Stack_operators);
	
	return postfix;
}

void ifGetdigit(char ch, string &postfix) {
	postfix.push_back(ch);
}

void ifGetOperator(char ch, string &postfix, stack<char> &Stack_operators) {
	switch (ch) {
	case '(':	isLeftParenthesis(ch, Stack_operators);				break;
	case ')':	isRightParenthesis(postfix, Stack_operators);		break;
	default :	isArithmeticOperator(ch, postfix, Stack_operators);	break;
	}
}

void isLeftParenthesis(char ch, stack<char> &Stack_operators){
		Stack_operators.push(ch);
}

void isRightParenthesis(string &postfix, stack<char> &Stack_operators){
	while (!(Stack_operators.top() == '(')) {
		postfix.push_back('#');
		postfix.push_back(Stack_operators.top());	
		Stack_operators.pop();
	}
	postfix.push_back('@');
	Stack_operators.pop();
}

void isArithmeticOperator(char ch, string &postfix, stack<char> &Stack_operators){
	map<char, int> priority;
	priority['+'] = 0;
	priority['-'] = 0;
	priority['*'] = 1;
	priority['/'] = 1;

	if (lastOneIsRightParenthesis(postfix))
		postfix.erase(postfix.end() - 1);
	else
		postfix.push_back('#');
	while (!Stack_operators.empty() && (Stack_operators.top() != '(')) {
		if (priority[ch] <= priority[Stack_operators.top()]) {
			postfix.push_back(Stack_operators.top());
			Stack_operators.pop();
		}
		else {
			break;
		}
	}
	Stack_operators.push(ch);
}

bool lastOneIsRightParenthesis(const string &postfix) {
	return *postfix.crbegin() == '@';
}

void appendOperatorsLeft(string &postfix, stack<char> Stack_operators) {
	if (lastOneIsRightParenthesis(postfix))
		postfix.erase(postfix.end() - 1);
	else
		postfix.push_back('#');
	while (!Stack_operators.empty()) {
		postfix.push_back(Stack_operators.top());
		Stack_operators.pop();
	}
}

double calculate(const string &postfix) {
	istringstream in(postfix);
	char operators;
	stack<double>  operand;

	while (!in.eof()) {
		operators = putOperandsIntoStack(in,operand);
		if (in.eof())
			break;
		singleOperate(operators,operand);
	}
	return operand.top();
}

char putOperandsIntoStack(istringstream &in,stack<double> &operand) {
	char ch;
	string doublestr;
	while ((in >> ch)) {
		if (isdigit(ch) || ch == '.') {
			while (ch != '#') {
				doublestr.push_back(ch);
				in >> ch;
			}
			operand.push(stod(doublestr));
			doublestr.clear();
		}
		else if (ch != '#') {
			break;
		}
	}
	return ch;
}

void singleOperate(char ch, stack<double> &operand) {
	double second = operand.top();
	operand.pop();
	double first = operand.top();
	operand.pop();
	switch (ch) {
	case '+':	operand.push(first + second);	break;
	case '-':	operand.push(first - second);	break;
	case '*':	operand.push(first * second);	break;
	case '/':	operand.push(first / second);	break;
	default:									break;
	}
}
